package com.gopay.common.util.encoding;

import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;

import org.apache.commons.lang3.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;


public class EncodingFilter implements Filter {
    /**
     * 编码.
     */
    protected String encoding = null;
    /**
     * 过滤适配.
     */
    protected FilterConfig filterConfig = null;
    /**
     * 是否忽略.
     */
    protected boolean ignore = true;
    /**
     * 忽略的请求地址 自定义解码方式
     */
    protected String ignoreUrls = null;
    /**
     * 需要做特殊编码的URL
     */
    protected String specialEncodingInfo = null;
    /**
     * 需要做特殊编码的URL(已解析好的配置)
     */
    protected Map specialEncodingMap = null;

    private static Log logger = LogFactory.getLog(EncodingFilter.class);

    /**
     * 销毁.
     */
    @Override
    public void destroy() {
        this.encoding = null;
        this.filterConfig = null;
    }

    /**
     * 过滤.
     *
     * @param request  ServletRequest
     * @param response ServletResponse
     * @param chain    FilterChain
     * @throws IOException      java.io.IOException
     * @throws ServletException javax.servlet.ServletException
     */
    @Override
    public void doFilter(ServletRequest request, ServletResponse response,
                         FilterChain chain) throws IOException, ServletException {
        logger.error("----encoding----" + request.getCharacterEncoding());
        if (ignore || (request.getCharacterEncoding() == null)) {
            String url = ((HttpServletRequest) request).getRequestURI();
            if (!isIgnoreUrl(url)) {// 如果url不被忽略则设置编码
                String encoding = selectEncoding(request);
                if (encoding != null) {
                    request.setCharacterEncoding(encoding);
                }
                logger.error("encoding:" + encoding);
            }
            if (isSpecialEncoding(url)) {//如果Url需要特殊设置编码
                String encoding = (String) this.specialEncodingMap.get(url);
                if (encoding != null) {
                    request.setCharacterEncoding(encoding);
                }
                logger.error("special encoding:" + encoding);
            }
        }
        chain.doFilter(request, response);
    }

    /**
     * @param url
     * @return 判断是否为需要做特殊编码的url
     */
    private boolean isSpecialEncoding(String url) {
        if (StringUtils.isNotEmpty(this.specialEncodingInfo)) {
            if (null == this.specialEncodingMap.get(url)) {
                return false;
            }
            return true;
        }
        return false;
    }

    /**
     * 初始化.
     *
     * @param filterConfig FilterConfig
     * @throws ServletException javax.servlet.ServletException
     */
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        this.filterConfig = filterConfig;
        this.encoding = filterConfig.getInitParameter("encoding");
        String value = filterConfig.getInitParameter("ignore");
        this.ignore = value == null || value.equalsIgnoreCase("true")
                || value.equalsIgnoreCase("yes");
        this.ignoreUrls = filterConfig.getInitParameter("ignoreUrls");
        this.specialEncodingInfo = filterConfig.getInitParameter("specialEncodingInfo");
        initSpecialEncodingInfo();
    }

    /**
     * 根据specialEncodingInfo初始化specialEncodingMap<br>
     * 比如specialEncodingInfo为"gbk|url1.do,utf8|url2.do"，则specialEncodingMap为{url1.do=gbk, url2.do=utf8}
     */
    private void initSpecialEncodingInfo() {
        this.specialEncodingMap = new HashMap();
        if (StringUtils.isNotEmpty(this.specialEncodingInfo)) {
            // 先替换掉所有空格
            String[] specialUrl = specialEncodingInfo.replaceAll("\\s+", "").split(",");
            if (specialUrl == null || specialUrl.length <= 0) {
                return;
            }
            for (int i = 0; i < specialUrl.length; i++) {
                if (StringUtils.isEmpty(this.specialEncodingInfo) || -1 == specialUrl[i].indexOf("|") || 2 != specialUrl[i].split("\\|").length) {
                    continue;
                }
                String[] encodeUrlGroup = specialUrl[i].split("\\|");
                String encode = encodeUrlGroup[0];
                String url = encodeUrlGroup[1];
                this.specialEncodingMap.put(url, encode);
            }
        }
    }

    /**
     * 获取编码方式.
     *
     * @param request ServletRequest
     * @return String
     */
    protected String selectEncoding(ServletRequest request) {
        return (this.encoding);
    }

    /**
     * 是否忽略统一编码
     *
     * @param url
     * @return true 忽略 false 不忽略
     */
    private boolean isIgnoreUrl(String url) {
        if (StringUtils.isNotEmpty(this.ignoreUrls)) {
            String[] ignoreUrl = ignoreUrls.split(",");
            if (url == null || ignoreUrl == null || ignoreUrl.length <= 0) {
                return false;
            }
            for (int i = 0; i < ignoreUrl.length; i++) {
                if (url.indexOf(ignoreUrl[i]) != -1) {
                    return true;
                }
            }
        }
        return false;
    }
}
